package org.example.mall.admin.configuration.resource;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author hzq
 * @date 2021/10/11 11:53
 */
@AllArgsConstructor
public class CustomBearerTokenExtractor extends BearerTokenExtractor {

    private final PermitAllUrl permitAllUrl;

    /**
     * 不需要认证的接口不提取认证信息
     */
    @Override
    public Authentication extract(HttpServletRequest request) {
        // inner.value() = false 时不提取token
        boolean result = permitAllUrl.getIgnoreUrls().stream().anyMatch(predicate(request));
        return result ? null : super.extract(request);
    }

    /**
     * /home
     * /home|false
     * GET /home 放行且不提取token
     * PUT /home 放行且不提取token
     * POST /home 放行且不提取token
     * DELETE /home 放行且不提取token
     * <p>
     * /home|true
     * GET /home 放行且提取token
     * PUT /home 放行且提取token
     * POST /home 放行且提取token
     * DELETE /home 放行且提取token
     * <p>
     * /home|GET,POST|true
     * GET /home 放行且提取token
     * PUT /home 提取token且需要认证
     * POST /home 放行且提取token
     * DELETE /home 提取token且需要认证
     * <p>
     * /home|GET,PUT,POST|false
     * GET /home 放行且不提取token
     * PUT /home 放行且不提取token
     * POST /home 放行且不提取token
     * DELETE /info 提取token且需要认证
     *
     * @return true 提取token false 不提取token
     */
    private Predicate<String> predicate(HttpServletRequest request) {
        return (String url) -> {
            List<String> splitTrim = StrUtil.splitTrim(url, permitAllUrl.SEPARATOR);
            // 1. 判断路径是否匹配 /home
            // 路径匹配
            boolean match = permitAllUrl.PATHMATCHER.match(splitTrim.get(0), request.getRequestURI());
            // 2. 判断路径是否匹配 && 判断inner.value() /home|true
            // 路径匹配 && inner.value()
            if (splitTrim.size() == 2) {
                return match && !Boolean.parseBoolean(splitTrim.get(1));
            }
            // 3. 判断方法是否匹配 && 判断路径是否匹配 && 判断inner.value() /home|GET,POST|true
            //  路径匹配 && inner.value() && 请求方法匹配
            if (splitTrim.size() == 3) {
                return match && !Boolean.parseBoolean(splitTrim.get(2)) &&
                        CollUtil.contains(StrUtil.splitTrim(splitTrim.get(1), StrUtil.COMMA), request.getMethod());
            }
            return match;
        };
    }

    public static CustomBearerTokenExtractor build(PermitAllUrl permitAllUrl) {
        return new CustomBearerTokenExtractor(permitAllUrl);
    }
}
